import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Iterator;
import java.util.Vector;

public class HandleClient implements Runnable {

	MyLogger ServerLog;
	private String nick;
	private Table table;
	private Socket ClientSocket;
	private TableManager TManager;
	private AllTableSocketList SList;

	public HandleClient(Socket sock, TableManager TManager, AllTableSocketList SList,MyLogger ServerLog)
	{
		this.ClientSocket = sock;
		this.ServerLog = ServerLog;
		this.TManager = TManager;
		
		this.SList = SList;
	}
	public void HandleCurrentClient()
	{
		Iterator iter = null;
		Message m = new Message("" , null);
		try {
			ObjectInputStream ois = new ObjectInputStream(ClientSocket.getInputStream());
			ObjectOutputStream oos = new ObjectOutputStream(ClientSocket.getOutputStream());
			
			m = (Message) ois.readObject();
			nick = (String) m.obj;
			m.MakeMessage("TableList", TManager.packTableList());
			oos.writeObject(m);
			oos.reset();
			
			m = (Message) ois.readObject();
			if(m.Code.equals("ChosenTableNumber"))
			{
				int tableNumber = Integer.parseInt((String) m.obj);
				table = TManager.TableList.get(tableNumber - 1);
				table.PManager.addPlayer(nick, table.CManager.getHoleCards());
				// Store user socket information
				SList.WholeList.elementAt(table.tableNumber - 1).tableSockets.addElement(new MySocket(nick,ClientSocket,oos));
				
			}
			
			if(table.GameInProgress)
				table.PManager.getPlayer(nick).setState("Queued");

			m.MakeMessage("SendingTable", table);
			broadcast(iter,m,false);
						
			// last player who joins sends your turn to currentPlayer
			if(table.PManager.getCountofPlayers() == 2){
				
				table.RManager.updateRoundID();
				table.PManager.getCurrentPlayer().setBet(10);
				iter = SList.WholeList.elementAt(table.tableNumber - 1).tableSockets.iterator();
				table.RManager.GameInProgress = true;
				m.MakeMessage("SendingTable", table);
				broadcast(iter,m,false);
				m.MakeMessage("GameStarting", null);
				broadcast(iter,m,false);

				table.GameInProgress = true;
				SendTurn(iter);
			}
			Player PlayerObj = null;
			while(true)
			{
				m = (Message) ois.readObject();
				
				if(m.Code.equals("PlayerChecked"))
				{
					PlayerObj = (Player) table.PManager.getCurrentPlayer(); // Get the player object
					table.PlayerChecked(PlayerObj, table.RManager.getCurrHigh()); // Updation
					table.TakeRoundAction(PlayerObj); // Take Appropriate Action
					if(table.isWinnerSet)
					{
						m.MakeMessage("WinnerDecided", table);
						broadcast(iter,m,false);
						table.RestartGame();
						m.MakeMessage("SendingTable", table);
						broadcast(iter,m,false);
						SendTurn(iter);
					}	
					else
					{
						broadcast(iter,new Message("SendingTable",table),false); //Broadcast the table
						table.PManager.updateCurrentPlayer(PlayerObj); //Update the current player
						SendTurn(iter); //Send your turn message to the next player
					}

				}// End of if(PlayerChecked)
				else if(m.Code.equals("PlayerFolded"))
				{
					PlayerObj = (Player) table.PManager.getCurrentPlayer(); //Get this player's object
					table.PlayerFolded(PlayerObj); // Updation
					table.TakeRoundAction(PlayerObj); // Take Appropriate Action
					if(table.isWinnerSet)
					{
						m.MakeMessage("WinnerDecided", table);
						broadcast(iter,m,false);
						table.RestartGame();
						m.MakeMessage("SendingTable", table);
						broadcast(iter,m,false);
						SendTurn(iter);
					}
					else
					{
						broadcast(iter,new Message("SendingTable",table),false); //Broadcast the table
						table.PManager.updateCurrentPlayer(PlayerObj); //Update the current player
						SendTurn(iter); //Send your turn message to the next player
					}
				}// End of if(PlayerFolded)
				else if(m.Code.equals("PlayerRaised"))
				{
					PlayerObj = (Player) table.PManager.getCurrentPlayer(); //Get this player's object
					table.PlayerRaised(PlayerObj, m.val); //Updation
					m.MakeMessage("SendingTable",table); //Prepare a message
					table.TakeRoundAction(PlayerObj); // Take Appropriate Action
					broadcast(iter,m,false); //Broadcast the table
					table.PManager.updateCurrentPlayer(PlayerObj); //Update the current player
					SendTurn(iter); //Send your turn message
				}// End of if(PlayerRaised)
				else if(m.Code.equals("PlayerCalled"))
				{
					PlayerObj = (Player) table.PManager.getCurrentPlayer(); //Get this Player's Object
					table.PlayerCalled(PlayerObj); // Updation
					m.MakeMessage("SendingTable", table); //Prepare a message
					table.TakeRoundAction(PlayerObj); // Take Appropriate Action
					broadcast(iter,m,false); //Broadcast the tables
					table.PManager.updateCurrentPlayer(PlayerObj); //Update the current player
					SendTurn(iter); // Send YourTurn Message
				}//End of if(PlayerCalled)
				if(m.Code.equals("Chat"))
				{
					String chat = (String) m.obj;
					table.ChManager.ChatData+= chat;
					broadcast(iter,m,true);
				}
				if(m.Code.equals("ClientClosing"))
				{
					table.PManager.removePlayer(table.PManager.getPlayer(nick));
					iter = SList.WholeList.elementAt(table.tableNumber - 1).tableSockets.iterator();
					while(iter.hasNext())
					{
						MySocket s = (MySocket) iter.next();
						if(s.nick.equals(nick))
						{
							s.oos.close();
							SList.WholeList.elementAt(table.tableNumber - 1).tableSockets.remove(s);
							break;
						}
					}
					if(SList.WholeList.elementAt(table.tableNumber - 1).tableSockets.isEmpty())
					{
						table.ChManager.ChatData = "";
						table.RManager.resetRoundID();
					}
					m.MakeMessage("SendingTable", table);
					broadcast(iter,m,true);
					ClientSocket.close();
					break;
				}
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
	public synchronized void SendTurn(Iterator iter)
	{
		iter = SList.WholeList.elementAt(table.tableNumber - 1).tableSockets.iterator();
		while(iter.hasNext())
		{
			MySocket sock = (MySocket) iter.next();
			Player player = table.PManager.getPlayer(sock.nick);
			if(player.isCurrPlayer)
			{
				Message m = new Message("YourTurn", null);
				try {
					sock.oos.writeObject(m);
					sock.oos.reset();
					break;
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
	public synchronized void broadcast(Iterator iter, Message m,boolean param)
	{
		iter = SList.WholeList.elementAt(table.tableNumber - 1).tableSockets.iterator();

		try {
			if(param)
			{
				while(iter.hasNext())
				{
					MySocket sock = (MySocket) iter.next();
					if(sock.mySocket != ClientSocket)
					{
						sock.oos.writeObject(m);
						sock.oos.reset();
					}
				}
			} //End of if(param)
			else
			{
				while(iter.hasNext())
				{
					MySocket sock = (MySocket) iter.next();
					sock.oos.writeObject(m);
					sock.oos.reset();
				}
			}

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			}
	}
	public void run()
	{
		HandleCurrentClient();
	}
}
